package com.sum.tea.xinlian.viewmodel

import android.app.Application
import android.util.Log
import androidx.lifecycle.*
import com.blankj.utilcode.util.ConvertUtils
import com.pow.api.cls.RfidPower
import com.power.OtherPower
import com.sum.tea.R
import com.sum.tea.contants.AppConfig
import com.uhf.api.cls.Reader
import com.uhf.api.cls.Reader.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class Sub1TabViewModel(application: Application) : AndroidViewModel(application) {

    private val mAppConfig = AppConfig.getInstance()
    // LiveData for module info
    private val _moduleInfo = MutableLiveData<String>()
    val moduleInfo: LiveData<String> get() = _moduleInfo

    // LiveData for connection state
    private val _isConnected = MutableLiveData<Boolean>(false)
    val isConnected: LiveData<Boolean> get() = _isConnected

    // LiveData for enabling/disabling buttons
    private val _canConnect = MutableLiveData<Boolean>(true)
    val canConnect: LiveData<Boolean> get() = _canConnect

    private val _canDisconnect = MutableLiveData<Boolean>(false)
    val canDisconnect: LiveData<Boolean> get() = _canDisconnect

    // LiveData for TabWidget visibility
    private val _tabsVisible = MutableLiveData<Boolean>(false)
    val tabsVisible: LiveData<Boolean> get() = _tabsVisible

    // Spinner data
    val pdaTypes: List<String> = RfidPower.getPdaPlat().apply { this[0] = AppConfig.No }.toList()
    val antPorts: List<String> = AppConfig.pdaatpot.toList()
    val baudRates: List<String> = listOf("4800", "9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600")

    // Preferences keys
    private val PDATYPE_KEY = "PDATYPE"
    private val ADDRESS_KEY = "ADDRESS"
    private val ANTPORT_KEY = "ANTPORT"
    private val BAUDRATE_KEY = "BAUDRATE"

    // State variables
    var isdefaultmaxpow_V: Boolean = false
    var isotherpowerup: Boolean = true

    // LiveData for Toast messages
    private val _toastMessage = MutableLiveData<String>()
    val toastMessage: LiveData<String> get() = _toastMessage

    // Functions to connect and disconnect
    fun connectReader(
        ip: String,
        selectedPdaType: Int,
        selectedAntPort: Int,
        selectedBaudRate: String
    ) {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                try {
                    if (ip.isEmpty()) {
                        // Post an event to show Toast in Activity
                        postToastMessage(getApplication<Application>().getString(R.string.Constr_sub1adrno))
                        return@withContext
                    }

                    if (mAppConfig.Rpower == null) {
                        postToastMessage(getApplication<Application>().getString(R.string.Constr_sub1pdtsl))
                        return@withContext
                    }

                    var blen = false

                    if (mAppConfig.Rpower.GetType() != RfidPower.PDATYPE.NONE) {
                        blen = mAppConfig.Rpower.PowerUp()
                        postToastMessage("${getApplication<Application>().getString(R.string.Constr_mainpu)}$blen")
                        if (!blen) return@withContext
                    } else {
                        if (isotherpowerup) {
                            OtherPower.oPowerUp()
                        }
                    }

                    var portc = when (selectedAntPort) {
                        5 -> 16
                        4 -> 8
                        else -> selectedAntPort + 1
                    }

                    var finalIp = ip
                    if (!ip.contains(".") && !ip.contains(":") && selectedBaudRate != "115200") {
                        finalIp += ":$selectedBaudRate"
                    }

                    val constV = System.currentTimeMillis()
                    Log.d("MYINFO", "connect finalIp: $finalIp ,port:$portc")
                    val er = mAppConfig.Mreader.InitReader_Notype(finalIp, portc)
                    Log.d("MYINFO", "connect cost time: ${System.currentTimeMillis() - constV}")

                    // Assume connection is successful as per original code
                    mAppConfig.needlisen = true
                    mAppConfig.needreconnect = false
                    mAppConfig.spf.SaveString(PDATYPE_KEY, selectedPdaType.toString())
                    mAppConfig.spf.SaveString(ADDRESS_KEY, ip)
                    mAppConfig.spf.SaveString(ANTPORT_KEY, selectedAntPort.toString())
                    mAppConfig.spf.SaveString(BAUDRATE_KEY, selectedBaudRate)

                    // Set inventory protocols
                    val invProtocols = Reader().Inv_Potls_ST().apply {
                        potlcnt = 1
                        potls = arrayOf(
                            Reader().Inv_Potl().apply {
                                weight = 30
                                potl = Reader.SL_TagProtocol.SL_TAG_PROTOCOL_GEN2
                            }
                        )
                    }
                    mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAG_INVPOTL, invProtocols)

                    val av = IntArray(1)
                    mAppConfig.Mreader.ParamGet(Mtr_Param.MTR_PARAM_READER_AVAILABLE_ANTPORTS, av)
                    mAppConfig.antportc = portc

                    // Handle UI updates on main thread
                    withContext(Dispatchers.Main) {
                        handleConnectUI()
                    }

                    mAppConfig.Address = finalIp
                    mAppConfig.haveinit = true

                    // Additional connection handling, like reading hardware details
                    readHardwareDetails()

                } catch (ex: Exception) {
                    Log.d("MYINFO", "${ex.message} ${ex.toString()}", ex)
                }
            }
        }
    }

    private suspend fun readHardwareDetails() {
        withContext(Dispatchers.IO) {
            try {
                var er: READER_ERR
                mAppConfig.Rparams = mAppConfig.spf.ReadReaderParams()

                if (isdefaultmaxpow_V) {
                    val mp = IntArray(1)
                    er = mAppConfig.Mreader.ParamGet(Mtr_Param.MTR_PARAM_RF_MAXPOWER, mp)
                    if (er == READER_ERR.MT_OK_ERR) {
                        mAppConfig.Rparams.setdefaulpwval(mp[0].toShort().toInt())
                    }
                }

                if (mAppConfig.Rparams.invpro.size < 1)
                    mAppConfig.Rparams.invpro.add("GEN2")

                val ltp = mutableListOf<SL_TagProtocol>()
                mAppConfig.Rparams.invpro.forEach {
                    when (it) {
                        "GEN2" -> ltp.add(SL_TagProtocol.SL_TAG_PROTOCOL_GEN2)
                        "6B" -> ltp.add(SL_TagProtocol.SL_TAG_PROTOCOL_ISO180006B)
                        "IPX64" -> ltp.add(SL_TagProtocol.SL_TAG_PROTOCOL_IPX64)
                        "IPX256" -> ltp.add(SL_TagProtocol.SL_TAG_PROTOCOL_IPX256)
                        else -> {}
                    }
                }

                val ipst = Reader().Inv_Potls_ST().apply {
                    potlcnt = ltp.size
                    potls = Array(potlcnt) {
                        Reader().Inv_Potl().apply {
                            weight = 30
                            potl = ltp[it]
                        }
                    }
                }

                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAG_INVPOTL, ipst)

                er = mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_READER_IS_CHK_ANT, intArrayOf(mAppConfig.Rparams.checkant))
                Log.d("MYINFO", "Connected set checkant: $er")

                val apcf: AntPowerConf = mAppConfig.Mreader.AntPowerConf()
                apcf.antcnt = mAppConfig.antportc
                for (i in 0 until apcf.antcnt) {
                    val jaap: AntPower = mAppConfig.Mreader.AntPower()
                    jaap.antid = i + 1
                    jaap.readPower = mAppConfig.Rparams.rpow[i].toShort()
                    jaap.writePower = mAppConfig.Rparams.wpow[i].toShort()
                    apcf.Powers[i] = jaap
                }
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_RF_ANTPOWER, apcf)

                val regionConf = when (mAppConfig.Rparams.region) {
                    0 -> Region_Conf.RG_PRC
                    1 -> Region_Conf.RG_NA
                    2 -> Region_Conf.RG_NONE
                    3 -> Region_Conf.RG_KR
                    4 -> Region_Conf.RG_EU
                    5 -> Region_Conf.RG_EU2
                    6 -> Region_Conf.RG_EU3
                    9 -> Region_Conf.RG_OPEN
                    10 -> Region_Conf.RG_PRC2
                    else -> Region_Conf.RG_NONE
                }
                if (regionConf != Region_Conf.RG_NONE) {
                    mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_FREQUENCY_REGION, regionConf)
                }

                if (mAppConfig.Rparams.frelen > 0) {
                    val hdst = Reader().HoptableData_ST().apply {
                        lenhtb = mAppConfig.Rparams.frelen
                        htb = mAppConfig.Rparams.frecys
                    }
                    mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_FREQUENCY_HOPTABLE, hdst)
                }

                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_SESSION, intArrayOf(mAppConfig.Rparams.session))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_Q, intArrayOf(mAppConfig.Rparams.qv))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_WRITEMODE, intArrayOf(mAppConfig.Rparams.wmode))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_MAXEPCLEN, intArrayOf(mAppConfig.Rparams.maxlen))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_POTL_GEN2_TARGET, intArrayOf(mAppConfig.Rparams.target))

                if (mAppConfig.Rparams.filenable == 1) {
                    val tfst = Reader().TagFilter_ST().apply {
                        bank = mAppConfig.Rparams.filbank
                        val len = if (mAppConfig.Rparams.fildata.length % 2 == 0) mAppConfig.Rparams.fildata.length else mAppConfig.Rparams.fildata.length + 1
                        fdata = ByteArray(len / 2)
                        mAppConfig.Mreader.Str2Hex(mAppConfig.Rparams.fildata, mAppConfig.Rparams.fildata.length, fdata)
                        flen = mAppConfig.Rparams.fildata.length * 4
                        startaddr = mAppConfig.Rparams.filadr
                        isInvert = mAppConfig.Rparams.filisinver
                    }
                    mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, tfst)
                }

                if (mAppConfig.Rparams.emdenable == 1) {
                    val edst = Reader().EmbededData_ST().apply {
                        accesspwd = null
                        bank = mAppConfig.Rparams.emdbank
                        startaddr = mAppConfig.Rparams.emdadr
                        bytecnt = mAppConfig.Rparams.emdbytec
                    }
                    mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAG_EMBEDEDDATA, edst)
                }

                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAGDATA_UNIQUEBYEMDDATA, intArrayOf(mAppConfig.Rparams.adataq))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAGDATA_RECORDHIGHESTRSSI, intArrayOf(mAppConfig.Rparams.rhssi))
                mAppConfig.Mreader.ParamSet(Mtr_Param.MTR_PARAM_TAG_SEARCH_MODE, intArrayOf(mAppConfig.Rparams.invw))

                // Read hardware details
                val valDetails = Reader().HardwareDetails()
                er = mAppConfig.Mreader.GetHardwareDetails(valDetails)

                if (er == READER_ERR.MT_OK_ERR) {
                    var sn = "" // Serial number
                    var bootver = "" // Boot version
                    var hardver = "" // Hardware version
                    var firmdata = "" // Firmware data
                    var firmver = "" // Firmware version

                    val cpara = Reader().CustomParam_ST().apply {
                        ParamName = "reader/moduleinfo"
                    }
                    val ret = mAppConfig.Mreader.ParamGet(Mtr_Param.MTR_PARAM_CUSTOM, cpara)
                    if (ret != READER_ERR.MT_OK_ERR) {
                        val rdrver = Reader().ReaderVersion()
                        mAppConfig.Mreader.ParamGet(Mtr_Param.MTR_PARAM_READER_VERSION, rdrver)
                        _moduleInfo.postValue("module:${valDetails.module}\r\nsoftwareVer:${rdrver.softwareVer}\r\nhardwareVer:${rdrver.hardwareVer}")
                    } else {
                        val binhv = ByteArray(28)
                        System.arraycopy(cpara.ParamVal, 16, binhv, 0, 28)
                        val temp = ByteArray(1)
                        var p = 0

                        for (i in 0 until 12) {
                            temp[0] = binhv[p++]
                            sn += ConvertUtils.bytes2HexString(temp)
                        }

                        temp[0] = binhv[p++]
                        bootver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        bootver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        bootver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        bootver += ConvertUtils.bytes2HexString(temp)

                        temp[0] = binhv[p++]
                        hardver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        hardver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        hardver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        hardver += ConvertUtils.bytes2HexString(temp)

                        temp[0] = binhv[p++]
                        firmdata += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmdata += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmdata += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmdata += ConvertUtils.bytes2HexString(temp)

                        temp[0] = binhv[p++]
                        firmver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmver += "${ConvertUtils.bytes2HexString(temp)}."
                        temp[0] = binhv[p++]
                        firmver += ConvertUtils.bytes2HexString(temp)

                        _moduleInfo.postValue("module:${valDetails.module}\r\nbootver:$bootver\r\nhardver:$hardver\r\nfirmdat:$firmdata\r\nfirmver:$firmver\r\nmodulesn:$sn")
                    }

                    mAppConfig.myhd = valDetails
                } else {
                    
                }

            } catch (ex: Exception) {
                Log.d("MYINFO", "${ex.message} ${ex.toString()}", ex)
            }
        }
    }

    fun disconnectReader() {
        viewModelScope.launch {
            withContext(Dispatchers.IO) {
                try {
                    if (mAppConfig.Mreader != null) {
                        mAppConfig.Mreader.CloseReader()
                        mAppConfig.needlisen = true
                        mAppConfig.haveinit = false
                    }

                    var blen = false

                    if (mAppConfig.Rpower?.GetType() != RfidPower.PDATYPE.NONE) {
                        blen = mAppConfig.Rpower.PowerDown()
                    } else {
                        if (isotherpowerup) {
                            OtherPower.oPowerDown()
                        }
                    }

                    postToastMessage("${getApplication<Application>().getString(R.string.Constr_disconpowdown)}$blen")
                    withContext(Dispatchers.Main) {
                        handleDisconnectUI()
                    }

                } catch (ex: Exception) {
                    Log.d("MYINFO", "${ex.message} ${ex.toString()}", ex)
                }
            }
        }
    }

    private fun handleConnectUI() {
        _isConnected.value = true
        _canConnect.value = false
        _canDisconnect.value = true
        _tabsVisible.value = true
    }

    private fun handleDisconnectUI() {
        _isConnected.value = false
        _canConnect.value = true
        _canDisconnect.value = false
        _tabsVisible.value = false
        _moduleInfo.value = ""
    }

    // Function to handle showing toast messages via LiveData
    private fun postToastMessage(message: String) {
        _toastMessage.postValue(message)
    }

    // Expose AppConfig if needed for Activity
    fun getAppConfig(): AppConfig {
        return mAppConfig
    }
}
